/*
 ============================================================================
 Name		: Client.cpp
 Author	  : wangli@opi-corp.com
 Copyright   : Your copyright notice
 Description : Static lib source file
 ============================================================================
 */

#include "Client.h"
#include "Service.h"
#include "RCallStack.h"

ClientSession::ClientSession()
{
    
}

ClientSession::~ClientSession()
{
    Close();
}

void ClientSession::ConnectL()
{
    User::LeaveIfError(CreateSession(KServiceName, Version()));
}

void ClientSession::CreateCallStack(const TDesC& aStackName, TInt aStackSize)
{
    __ASSERT_DEBUG(aStackName.Length() > 0 && 
                   aStackName.Length() < KMaxFullName &&
                   aStackSize > 0, User::Invariant());
    
    TIpcArgs args;
    TBuf<KMaxFullName> stackRequestParam;
    stackRequestParam.Append(aStackName);
    args.Set(0, &stackRequestParam);
    args.Set(1, aStackSize);
    User::LeaveIfError(SendReceive(ECreateStack, args));
    iStack.OpenL(aStackName);
}

void ClientSession::ClientLeave()
{
    SendReceive(EClientLeave);
}

void ClientSession::Close()
{
    if(iStack.IsAvaliable())
    {
        SendReceive(ECloseSession);
        iStack.Close();
    }
    RSessionBase::Close();
}

TVersion ClientSession::Version()const
{
    return TVersion(KPanicServerMajorVersionNumber, 
               KPanicServerMinorVersionNumber, KPanicServerBuildVersionNumber);
}

TClientEntry::~TClientEntry()
{
    if(iInstance != NULL)
    {
        delete iInstance;
        iInstance = NULL;
    }
}

TClientEntry CClient::gInstanceMap[CClient::KMaxClientNumber];
TInt CClient::gCurrentCount = 0;

CClient* CClient::InstanceL(const TDesC& aClientName, TInt aStackSize)
{
    if(aClientName.Length() == 0 || 
        aClientName.Length() > KMaxFullName)
        User::Leave(KErrArgument);

    //TODO: 加锁
    for(TInt index = 0; index < gCurrentCount; ++index)
    {
        if(aClientName == gInstanceMap[index].iClientName)
            return gInstanceMap[index].iInstance;
    }

    if(gCurrentCount >= KMaxClientNumber)
    {
        //TODO: 解锁
        User::Leave(KErrFull);
    }


    CClient* aNewClient = NULL;
    TRAPD(err, aNewClient = CClient::NewL(aClientName, aStackSize));
    if(err != KErrNone)
    {
        //TODO：解锁
        User::Leave(ELeave);
    }
    gInstanceMap[gCurrentCount].iClientName.Append(aClientName);
    gInstanceMap[gCurrentCount].iInstance = aNewClient;
    ++gCurrentCount;
    //TODO: 解锁   
   
    return aNewClient;
}

void CClient::FreeAllInstance()
{
    TInt index = 0;
    for(index = 0; index < gCurrentCount; ++index)
    {
        gInstanceMap[index].iClientName.SetLength(0);
        if(gInstanceMap[index].iInstance)
        {
            delete gInstanceMap[index].iInstance;
            gInstanceMap[index].iInstance = NULL;
        }
    }
    gCurrentCount = 0;
}

void CClient::CloseInstance(const TDesC& aClientName)
{
    //TODO: 加锁
    TInt index = 0;
    for(index = 0; index < gCurrentCount; ++index)
    {
        if(aClientName == gInstanceMap[index].iClientName)
            break;
    }
    if(index < gCurrentCount)
    {
        if(gInstanceMap[index].iInstance)
        {
            delete gInstanceMap[index].iInstance;
            gInstanceMap[index].iInstance = NULL;
        }
        //移动后面的元素到前面
        for(TInt temp = index + 1; temp < gCurrentCount; ++temp)
        {
            gInstanceMap[temp - 1].iClientName.SetLength(0);
            gInstanceMap[temp - 1].iClientName.Append(gInstanceMap[temp].iClientName);
            gInstanceMap[temp - 1].iInstance = gInstanceMap[temp].iInstance;
        }

        --gCurrentCount;
        //TODO: 解锁
    }
    
}

CClient* CClient::NewL(const TDesC& aClientName, TInt aStackSize)
{
    CClient* result = new(ELeave) CClient();
    result->ConstuctL(aClientName, aStackSize);
    return result;
}

void CClient::ConstuctL(const TDesC& aClientName, TInt aStackSize)
{
    iSession.ConnectL();
    iSession.CreateCallStack(aClientName, aStackSize);
}

CClient::CClient()
{
    
}

CClient::~CClient()
{
    iSession.Close();
}
